#!/bin/bash
#
# Copyright 2015-2017 Adrian DC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

# === Standalone Source Helper ===
# source <(curl -Ls https://github.com/AdrianDC/android_development_shell_tools/raw/master/android_kernel_defconfig.rc)

# === Kernel DefConfig Editor ===
function makedefconf()
{
  # Usage
  if [ -z "${1}" ]; then
    echo '';
    echo '  Usage: makedefconf <device_name> [bool_full_config] [diff_config] [force_config=value] (Advanced defconfig helper)';
    echo '';
    return;
  fi;

  # Variables
  local defconfig=${1};
  local configmode=${2};
  local diffcommon=${3};
  local forceconfig=${4};
  local defconfig_file;
  local diffconfig;

  # DiffConfig
  diffconfig=$(ls "arch/arm"*"/configs/diffconfig/${configmode}_diffconfig" 2> /dev/null);
  if [ ! -z "${diffconfig}" ] && [ -f "${diffconfig}" ]; then
    export ARCH;
    export KBUILD_DIFFCONFIG;
    ARCH=$(echo "${diffconfig}" | sed 's/.*\(arm[^\/]*\)\/.*/\1/');
    KBUILD_DIFFCONFIG=${configmode}_diffconfig;
    diffcommon=$(dirname "${diffconfig}")/${diffcommon}_diffconfig;
  fi;

  # Architecture
  export SUBARCH=arm;
  export KCONFIG_NOTIMESTAMP=true;

  # Detect arm / arm64
  export ARCH=arm;
  local DEFCONFIG_CHECKS;
  for arch_check in arm arm64; do
    DEFCONFIG_CHECKS=("./arch/${arch_check}/configs/"*"${defconfig}"*);
    if [ ${#DEFCONFIG_CHECKS[@]} -eq 1 ] && [ -f "${DEFCONFIG_CHECKS[*]}" ]; then
      export ARCH=${arch_check};
      break;
    fi;
  done;

  # Kernel input
  local DEFCONFIG_PATH=./arch/${ARCH}/configs;
  local DEFCONFIG_INPUTS=("${DEFCONFIG_PATH}/"*"${defconfig}"*);
  local DEFCONFIG_INPUT="${DEFCONFIG_INPUTS[*]}";

  # Handle looped forced config
  if [ ! -z "${forceconfig}" ] && [ ${#DEFCONFIG_INPUTS[@]} -gt 1 ]; then
    for defconfig in ${DEFCONFIG_INPUTS[*]}; do
      makedefconf "${defconfig##*/}" "${configmode}" "${diffcommon}" "${forceconfig}";
    done;
    return;

  # Handle failed defconfig selection
  elif [ ${#DEFCONFIG_INPUTS[@]} -ne 1 ] || [ ! -f "${DEFCONFIG_INPUTS[*]}" ]; then
    if [ ${#DEFCONFIG_INPUTS[@]} -eq 1 ]; then
      echo '';
      echo '  Error: makedefconf found no defconfigs';
      echo '';
      return;
    fi;

    # Create defconfig selector list
    local cnt=0;
    echo '';
    echo '  Warning: makedefconf found '${#DEFCONFIG_INPUTS[@]}' defconfigs';
    echo '';
    for defconfig_path in "${DEFCONFIG_INPUTS[@]}"; do
      cnt=$((cnt + 1));
      echo "   ${cnt}: ${defconfig_path}";
    done;
    echo '';
    echo -n "  Defconfig to use [1 to {cnt}] : ";
    read -r key;
    key=$((key - 1));
    if [ ${key} -ge 0 ] && [ ${key} -lt ${cnt} ]; then
      DEFCONFIG_INPUT=${DEFCONFIG_INPUTS[${key}]};
    else
      DEFCONFIG_INPUT=;
    fi;

    # Validate user choice
    if [ ! -f "${DEFCONFIG_INPUT}" ]; then
      echo '';
      echo '  Error: makedefconf found no defconfigs';
      echo '';
      return;
    fi;
  fi;

  # Kernel defconfig
  defconfig_file=$(basename "${DEFCONFIG_INPUT}");

  # Google configurations
  if [[ "${defconfig}" == 'google' ]]; then
    ./scripts/kconfig/merge_config.sh "${DEFCONFIG_PATH}/${defconfig_file}" android/configs/android-base.cfg android/configs/android-recommended.cfg
    mv ./.config ./.config_android;
    make "${defconfig_file}";
    if [ ! -z "${forceconfig}" ]; then
      kernelconfigupdater "${forceconfig}";
    fi;
    meld ./.config ./.config_android;
    rm ./.config_android;

  # Make full defconfig
  elif [ ! -z "${configmode}" ]; then
    make "${defconfig_file}";
    if [ ! -z "${forceconfig}" ]; then
      kernelconfigupdater "${forceconfig}";
    fi;
    if [ -f "${diffconfig}" ]; then
      if [ -f "${diffcommon}" ]; then
        meld ./.config "${diffconfig}" &
          meld ./.config "${diffcommon}" &
          meld ./.config "${DEFCONFIG_PATH}/${defconfig_file}";
      else
        meld ./.config "${diffconfig}" &
          meld ./.config "${DEFCONFIG_PATH}/${defconfig_file}";
      fi;
    else
      meld ./.config "${DEFCONFIG_PATH}/${defconfig_file}";
    fi;

  # Make minimal defconfig
  else
    make "${defconfig_file}";
    if [ ! -z "${forceconfig}" ]; then
      kernelconfigupdater "${forceconfig}";
    fi;
    make savedefconfig;
    meld ./defconfig "${DEFCONFIG_PATH}/${defconfig_file}";
    rm ./defconfig;
  fi;

  # Cleanup
  make mrproper;
  #rm -rf scripts/basic;
  #rm -rf scripts/kconfig;
  #rm -rf .config;
}

# === Kernel Config Updater ===
function kernelconfigupdater()
{
  # Usage
  if [ -z "${1}" ]; then
    echo '';
    echo '  Usage: kernelconfigupdater <CONFIG_NAME=VALUE_or_# CONFIG_NAME is not set> (Kernel config updater)';
    echo '';
    return;
  fi;

  # Detect .config
  if [ ! -f .config ]; then
    echo '';
    echo '  Error: .config was not found';
    echo '';
    return;
  fi;

  # Configuration variables
  local config_string=("${@}")
  local config_name;
  local config_output;

  # Configuration parsing
  if [ "${config_string[0]:0:1}" = "#" ]; then
    config_name=${config_string[1]};
    config_output="# ${config_name} is not set";
  else
    config_name=${config_string[*]%%=*};
    config_output="${config_name}=${config_string[*]##*=}";
  fi;

  # Configuration output
  sed -i "/# ${config_name} is not set/d" .config;
  sed -i "/${config_name}=/d" .config;
  echo "${config_output}" >> .config;
  rm -f .config.old;
  cp .config .config.old;

  # Update .config
  make oldconfig;
}

# === Kernel DefConfig Setter ===
function makedefconfset()
{
  # Usage
  if [ -z "${1}" ]; then
    echo '';
    echo '  Usage: makedefconfset <device_name> [force_config=value] (Kernel defconfig configuration setter)';
    echo '';
    return;
  fi;

  # Use makedefconf
  makedefconf "${1}" '' '' "${2}";
}
